﻿using Sttplay.Net.UDP;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Media.Imaging;

namespace transmission
{
    public class UDPContext : Context
    {

        public IPAddress localIP, remoteIP, groupIP;
        public int localPort, remotePort, groupPort;
        public bool reliable = false;
        private TreeViewItem treeItem;
        private StackPanelEx stack;
        private Image icon;
        private RUDPEx rudp;
        private RUDPEx_C rudp_c;
        private TextBlock textBlock;
        public bool isGroupcastMode = false;
        public UDPContext()
        {
            treeItem = new TreeViewItem();
            treeItem.IsExpanded = true;
            stack = new StackPanelEx();
            stack.Orientation = Orientation.Horizontal;
            treeItem.Header = stack;
            icon = new Image();
            icon.VerticalAlignment = VerticalAlignment.Center;
            icon.Height = 15;
            icon.Width = 15;
            icon.Margin = new Thickness(0, 0, 4, 0);
            icon.Source = new BitmapImage(new Uri("pack://application:,,,/res/net_run.png"));
            stack.Children.Add(icon);
            textBlock = new TextBlock();
            textBlock.VerticalAlignment = VerticalAlignment.Center;
            stack.Children.Add(textBlock);
            treeItem.IsSelected = true;
            stack.user = this;
            stack.type = TransmissionType.Udp;
            try
            {
                rudp_c = new RUDPEx_C();
                rudp_c.onRecv += OnRecv;
                rudp_c.onSend += OnSend;
                rudp_c.SetOption(RCTP.Option.MAX_RESENT_GROUP_COUNT, 2);
                rudp_c.SetOption(RCTP.Option.DEFAULT_TIMEOUT, 50);
                rudp_c.SetOption(RCTP.Option.MAX_RESEND_TIMEOUT, 2000);
                rudp_c.SetOption(RCTP.Option.MULTIPLE, 1.5f);
                rudp_c.SetOption(RCTP.Option.RESET_TIME, 1);
            }
            catch
            {

                rudp = new RUDPEx();
                rudp.onRecv += OnRecv;
                rudp.onSend += OnSend;
                rudp.SetOption(RCTP.Option.MAX_RESENT_GROUP_COUNT, 2);
                rudp.SetOption(RCTP.Option.DEFAULT_TIMEOUT, 50);
                rudp.SetOption(RCTP.Option.MAX_RESEND_TIMEOUT, 2000);
                rudp.SetOption(RCTP.Option.MULTIPLE, 1.5f);
                rudp.SetOption(RCTP.Option.RESET_TIME, 1);
            }
        }

        private void OnSend(RCTP.Message msg, RCTP.SendState state)
        {
            if (state == RCTP.SendState.MaxTimeout)
            {
                LogText = string.Format("[{0}] {1} : {2}", DateTime.Now.ToString("HH:mm:ss"), "RUDP send error", state);
                MainWindow.Instance.OnTipbarLog(this, LogText);
            }
        }

        public override void Tick()
        {
            if (!needUpdateUI) return;
            needUpdateUI = false;
            RecvText = string.Join("\n", recvList.ToArray());
            MainWindow.Instance.UpdateContextText(this);
        }

        private void OnRecv(byte[] buffer, bool reliable, EndPoint endPoint)
        {
            string msg = GetRecvBuffer(buffer);
            OnRecvImp(msg, "接收");
        }

        private void OnRecvImp(string msg, string extend)
        {
            recvList.Add(string.Format("[{0} {1}] {2}", DateTime.Now.ToString("HH:mm:ss"), extend, msg));
            while (recvList.Count > MAX_SHOW_LINE)
                recvList.RemoveAt(0);
            RecvText = string.Join("\n", recvList.ToArray());
            needUpdateUI = true;
        }

        public bool InitUdp(string remoteip, int remoteport, string localip, int localport, bool reliable)
        {
            isGroupcastMode = false;
            this.reliable = reliable;
            remoteIP = IPAddress.Parse(remoteip);
            remotePort = remoteport;
            bool ret = rudp_c != null ? rudp_c.Initialize(IPAddress.Parse(localip), localport) : rudp.Initialize(IPAddress.Parse(localip), localport);
            if (!ret)
            {
                if (rudp_c != null)
                    rudp_c.Terminate();
                else
                    rudp.Terminate();
                return false;
            }
            if(rudp_c != null)
            {
                IPEndPoint localEP = rudp_c.GetLocalEndPoint();
                localIP = localEP.Address;
                localPort = localEP.Port;
            }
            else
            {
                localIP = (rudp.Socket.LocalEndPoint as IPEndPoint).Address;
                localPort = (rudp.Socket.LocalEndPoint as IPEndPoint).Port;
            }
            textBlock.Text = string.Format("{0}:{1}", localIP.ToString(), localPort);
            return ret;
        }

        public bool InitUdpGroup(string groupcastip, int groupport, string localip)
        {
            isGroupcastMode = true;
            groupIP = IPAddress.Parse(groupcastip);
            groupPort = groupport;
            bool ret = rudp_c != null ? rudp_c.Initialize(IPAddress.Parse(localip), groupport) : rudp.Initialize(IPAddress.Parse(localip), groupport);
            if (!ret)
            {
                if (rudp_c != null)
                    rudp_c.Terminate();
                else
                    rudp.Terminate();
                return false;
            }
            
            if (rudp_c != null)
            {
                rudp_c.JoinMulticastGroup(groupIP);
                IPEndPoint localEP = rudp_c.GetLocalEndPoint();
                localIP = localEP.Address;
                localPort = localEP.Port;
            }
            else
            {
                rudp.JoinMulticastGroup(groupIP);
                localIP = (rudp.Socket.LocalEndPoint as IPEndPoint).Address;
                localPort = (rudp.Socket.LocalEndPoint as IPEndPoint).Port;
            }
            textBlock.Text = string.Format("{0}:{1}", localIP.ToString(), localPort);
            return true;
        }

        public TreeViewItem GetTreeViewItem()
        {
            return treeItem;
        }

        public void Terminate()
        {
            if (rudp_c != null)
                rudp_c.Terminate();
            else
                rudp.Terminate();
        }

        public override void Send()
        {
            string str;
            byte[] bs = GetSendBuffer(out str);
            if (bs == null)
                return;
          
            if (isGroupcastMode)
            {
                if(rudp_c != null)
                    rudp_c.SendTo(bs, 0, bs.Length, new IPEndPoint(groupIP, groupPort), false);
                else
                    rudp.SendTo(bs, 0, bs.Length, new IPEndPoint(groupIP, groupPort), false);
            }
            else
            {
                if(rudp_c != null)
                    rudp_c.SendTo(bs, 0, bs.Length, new IPEndPoint(remoteIP, remotePort), reliable);
                else
                    rudp.SendTo(bs, 0, bs.Length, new IPEndPoint(remoteIP, remotePort), reliable);
            }
            OnRecvImp(str, "发送");
            LogText = "";
            MainWindow.Instance.OnTipbarLog(this, LogText);
        }

        public override void Update()
        {
            base.Update();
            if (rudp_c != null)
                rudp_c.Update();
            else
                rudp.Update();
        }
    }
}
